////////////////////////////////////////////////
// DESCRIPTION:
//    Emulator LCD Control
//
// Legal Notices:
//   Copyright (c) 2008, Telliam Consulting, LLC.
//   All rights reserved.
//
//   Redistribution and use in source and binary forms, with or without modification,
//   are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice, this list
//     of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice, this
//     list of conditions and the following disclaimer in the documentation and/or other
//     materials provided with the distribution.
//   * Neither the name of Telliam Consulting nor the names of its contributors may be
//     used to endorse or promote products derived from this software without specific
//     prior written permission.
//
//   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//   SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
//   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
//   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//   DAMAGE. 
//

using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using Microsoft.SPOT.Emulator.Lcd;

namespace FusionWare.SPOT.EmulatorComponents
{
    /// <summary>
    /// This control provides support for a graphical LCD for use in .NET Micro Framework
    /// custom emulators.
    /// </summary>
    /// <remarks>
    /// The LcdControl supports creating custom emulators for the .NET Micro Framework.
    /// It implements all the functionality needed for displaying the graphics for the
    /// system. The LcdDisplay property identifies the emulator component that will generate
    /// the DevicePaint events for the system. The LcdControl connects to those events so that
    /// changes in the display state are automatically updated in the control.
    /// </remarks>
    public class LcdControl : Control, IEmulatorComponentControl
    {
        /// <summary>Creates a new instance of the LcdControl class</summary>
        /// <remarks>
        /// Standard default constructor
        /// </remarks>
        public LcdControl()
        {
            this.BackColor = Color.Black;
            this._lcd = new LcdDisplay();
            this._lcd.OnDevicePaint += new OnDevicePaintEventHandler(this.OnDevicePaint);
            this._ColorDepth = 16;
        }

        /// <summary>Register the LcdDisplay with the emulator</summary>
        /// <param name="Emulator">Emulator to register the port with</param>
        /// <remarks>
        /// This method will register the LcdDisplay with the Emulator
        /// </remarks>
        public void RegisterComponents(CustomEmulator Emulator)
        {
            if( Emulator == null )
                throw new ArgumentNullException( "Emulator" );

            this._lcd.Height = this.Height;
            this._lcd.Width = this.Width;
            this._lcd.BitsPerPixel = this._ColorDepth;
            Emulator.RegisterComponent(this._lcd);
        }

        private void OnDevicePaint( object sender, OnDevicePaintEventArgs args )
        {
            Rectangle clonerect = new Rectangle(new Point(0,0), args.Bitmap.Size);
            this.PaintArgs = new OnDevicePaintEventArgs(args.Rectangle, (Bitmap)args.Bitmap.Clone(clonerect, this.PixelFormat));
            base.Invalidate(args.Rectangle);
        }

        private PixelFormat PixelFormat
        {
            get 
            {
                if(this._PixelFormat == PixelFormat.Undefined)
                {
                    switch(this._ColorDepth)
                    {
                    case 8:
                        this._PixelFormat = PixelFormat.Format8bppIndexed;
                        break;

                    case 16:
                        this._PixelFormat = PixelFormat.Format16bppRgb565;
                        break;

                    case 24:
                        this._PixelFormat = PixelFormat.Format24bppRgb;
                        break;

                    case 32:
                        this._PixelFormat = PixelFormat.Format32bppArgb;
                        break;
                    }
                }
                return this._PixelFormat;
            }
        }
        PixelFormat _PixelFormat = PixelFormat.Undefined;

        /// <summary>Draws the bitmap for the LCD when the screen needs updating</summary>
        /// <param name="e">Standard Paint Args</param>
        protected override void OnPaint( PaintEventArgs e )
        {
            if( this.PaintArgs != null )
                e.Graphics.DrawImage(this.PaintArgs.Bitmap, this.PaintArgs.Rectangle );

            if( base.DesignMode )
                this.OnPaintDesignMode( e );

            base.OnPaint( e );
        }

        /// <summary>Paints the control background</summary>
        /// <param name="pevent">Stadard Paint Event Args</param>
        /// <remarks>
        /// Supports design mode by painting the background if the emulator 
        /// has not provided any image to display.
        /// </remarks>
        protected override void OnPaintBackground( PaintEventArgs pevent )
        {
            if(this.PaintArgs == null)
                base.OnPaintBackground( pevent );
        }

        private void OnPaintDesignMode( PaintEventArgs e )
        {
            Color penColor;
            Rectangle rectangle1 = base.ClientRectangle;
            if( this.BackColor.GetBrightness() < 0.5 )
                penColor = ControlPaint.Light( this.BackColor );
            else
                penColor = ControlPaint.Dark( this.BackColor );

            using( Pen pen = new Pen( penColor ) )
            {
                pen.DashStyle = DashStyle.Dash;
                rectangle1.Width--;
                rectangle1.Height--;
                e.Graphics.DrawRectangle( pen, rectangle1 );
            }
        }

        /// <summary>Emulator LCD Display component for this control</summary>
        public Microsoft.SPOT.Emulator.Lcd.LcdDisplay LcdDisplay
        {
            get { return this._lcd; }
        }

        /// <summary>Color Depth for the emulated LCD</summary>
        [
            CategoryAttribute("Appearance"),
            DescriptionAttribute("Color depth reported to the emulation system for this LCD."),
            DefaultValue(16)
        ]
        public int ColorDepth
        {
            get { return this._ColorDepth; }
            set { this._ColorDepth = value; }
        }
        private int _ColorDepth;

        private OnDevicePaintEventArgs PaintArgs;
        private Microsoft.SPOT.Emulator.Lcd.LcdDisplay _lcd;
    }
}

